﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using Bestcode.MathParser;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace Tubes4_Metnum.Machine
{
    public class GaussLegendreElement
    {
        public List<double> C;
        public List<double> X;

        public GaussLegendreElement()
        {
            C = null;
            X = null;
        }

        public void setC(IEnumerable<double> C)
        {
            this.C = new List<double>();
            this.C = C.ToList<double>();
        }

        public void setX(IEnumerable<double> X)
        {
            this.X = new List<double>();
            this.X = X.ToList<double>();
        }
    }

    public class GaussLegendre
    {
        public Dictionary<int, GaussLegendreElement> GaussLegendreDict;
        public int nVar;
        public String[] exp;
        public double[] a;
        public double[] b;
        public double[] orde;
        public double[] dataX;
        public double[] dataY;
        public double[] suku;
        public double[] tempRes;
        public double result;

        public GaussLegendre()
        {
            GaussLegendreDict = new Dictionary<int, GaussLegendreElement>();
            InitDictionary();
            nVar = 1;
            exp = new String[2];
            a = new double[2];
            b = new double[2];
            orde = new double[2];
            dataX = new double[2];
            dataY = new double[2];
            suku = new double[2];
            tempRes = new double[2];
            result = 0.0f;
        }

        private Dictionary<int, GaussLegendreElement> InitDictionary()
        {
            // orde = 2
            GaussLegendreElement elmt = new GaussLegendreElement();
            elmt.setC(new List<double> { 1.0, 1.0 });
            elmt.setX(new List<double> { -0.577350269, 0.577350269 });
            GaussLegendreDict.Add(2, elmt);
            // orde = 3
            elmt = new GaussLegendreElement();
            elmt.setC(new List<double> { 0.555555556, 0.888888889, 0.555555556 });
            elmt.setX(new List<double> { -0.774596669, 0.0, -0.774596669 });
            GaussLegendreDict.Add(3, elmt);
            // orde = 4
            elmt = new GaussLegendreElement();
            elmt.setC(new List<double> { 0.347854845, 0.652145155, 0.652145155, 0.347854845 });
            elmt.setX(new List<double> { -0.861136312, -0.339981044, 0.339981044, 0.861136312 });
            GaussLegendreDict.Add(4, elmt);
            // orde = 5
            elmt = new GaussLegendreElement();
            elmt.setC(new List<double> { 0.236926885, 0.478628670, 0.568888889, 0.478628670, 0.236926885 });
            elmt.setX(new List<double> { -0.906179846, -0.538469310, 0.0, 0.538469310, 0.906179846 });
            GaussLegendreDict.Add(5, elmt);
            // orde = 6
            elmt = new GaussLegendreElement();
            elmt.setC(new List<double> { 0.171324492, 0.360761573, 0.467913935, 0.467913935, 0.360761573, 0.171324492 });
            elmt.setX(new List<double> { -0.932469514, -0.661209386, -0.238619186, 0.238619186, 0.661209386, 0.932469514 });
            GaussLegendreDict.Add(6, elmt);
            
            return GaussLegendreDict;
        }

        public void PrintDictionary()
        {
            try
            {
                System.Console.WriteLine("Tabel Gauss-Legrendre");
                int tempc, tempx, key;
                for (int i = 0; i < GaussLegendreDict.Keys.Count; i++)
                {
                    key = GaussLegendreDict.Keys.ElementAt(i);
                    System.Console.WriteLine("orde = "+key);

                    System.Console.WriteLine("Faktor Bobot");
                    tempc = 0;
                    foreach (double c in GaussLegendreDict[key].C)
                    {
                        System.Console.WriteLine("c" + tempc + " = " + c);
                        tempc++;
                    }

                    System.Console.WriteLine("Argumen Fungsi");
                    tempx = 0;
                    foreach (double x in GaussLegendreDict[key].X)
                    {
                        System.Console.WriteLine("x" + tempx + " = " + x);
                        tempx++;
                    }
                }
            }
            catch (Exception exc)
            {
                System.Console.WriteLine(exc.Message);
                System.Console.WriteLine(exc.StackTrace);
            }
        }

        private String ChangeExpression(String exp, double a, double b, out double coef)
        {
            String retexp = "";
            retexp = "(" + ((a + b) / 2) + "+" + ((b - a) / 2) + "*x)";
            coef = (b - a) / 2;
            return retexp;
        }

        public double Integral(int orde, String exp, double a, double b)
        {
            double value = 0.0;

            MathParser parser = new MathParser();
            parser.Expression = exp;
            value = Integral(orde, parser, a, b);
            
            return value;
        }

        public double Integral(int orde, MathParser parser, double a, double b)
        {
            this.result = 0.0f;
            double coef = 1.0;
            try
            {
                this.nVar = 1;
                this.a[0] = a;
                this.b[0] = b;
                this.orde[0] = orde;

                // System.Console.WriteLine("DEBUG");
                GaussLegendreElement element = GaussLegendreDict[orde];
                this.dataX = new double[element.C.Count];
                this.dataY = new double[element.C.Count];
                this.suku = new double[element.C.Count];
                
                if (a != -1 || b != 1) // Bukan selang
                {
                    this.exp = new String[2];
                    this.exp[0] = parser.Expression;
                    String newExp = ChangeExpression(parser.Expression, a, b, out coef);
                    // System.Console.WriteLine("Expression = " + parser.Expression);
                    // System.Console.WriteLine("Substitution = " + newExp);
                    // System.Console.WriteLine("Coefisien = " + coef); 
                    
                    parser.Expression = parser.Expression.Replace("exp", "eksp");
                    // System.Console.WriteLine("Expression = " + parser.Expression);
                    
                    parser.Expression = parser.Expression.Replace("x", newExp);
                    parser.Expression = parser.Expression.Replace("eksp", "exp");
                    // System.Console.WriteLine("Expression = " + parser.Expression);
                    this.exp[1] = parser.Expression;
                }
                else 
                {
                    this.exp = new String[1];
                    this.exp[0] = parser.Expression;
                }

                for (int i = 0; i < element.C.Count; i++ )
                {
                    parser.X = element.X[i];
                    dataX[i] = element.X[i];
                    System.Console.WriteLine("x"+i+" = "+parser.X);
                    dataY[i] = (double) parser.Value;
                    suku[i] = element.C[i] * dataY[i];
                    this.result += suku[i];
                    System.Console.WriteLine("operasi:" + element.C[i] + " * " + (double) parser.Value);
                }

                this.result = this.result * coef;
            }
            catch (Exception exc)
            {
                this.result = 0.0f;

                System.Console.WriteLine(exc.Message);
                System.Console.WriteLine(exc.StackTrace);
            }
            return this.result;
        }

        public double IntegralGanda(int orde, String exp, double[] a, double[] b)
        {
            throw (new NotImplementedException());
        }

        public void saveFile(string filePath)
        {
            Document document = new Document();
            try
            {
                string ext = filePath.Substring(filePath.Length - 4, 4);
                if (ext.CompareTo(".pdf") != 0) filePath += ".pdf";
                PdfWriter.GetInstance(document, new FileStream(filePath, FileMode.Create));
                document.Open();

                /* untuk Gauss Legendre */
                document.Add(new Paragraph("Metode Gauss Legendre"));
                if (this.exp.Length == 1)
                {
                    Paragraph exp_par = new Paragraph("Fungsi :" + this.exp[0]);
                    document.Add(exp_par);
                }
                else
                {
                    Paragraph exp_par = new Paragraph("Fungsi asli :" + this.exp[0]);
                    exp_par.KeepTogether = true;
                    document.Add(exp_par);
                    exp_par = new Paragraph("Perubahan Fungsi :" + this.exp[1]);
                    document.Add(exp_par);
                }

                PdfPTable ptable;
                PdfPCell pcell;
                if (this.nVar == 1)
                {
                    document.Add(new Paragraph("a = " + this.a[0] + "; b = " + this.b[0] + "; orde = " + this.orde[0]));
                    ptable = new PdfPTable(3);
                    iTextSharp.text.Font arial7 = FontFactory.GetFont("ARIAL", 7);
                    pcell = new PdfPCell(new Phrase(new Chunk("X", arial7)));
                    ptable.AddCell(pcell);
                    pcell = new PdfPCell(new Phrase(new Chunk("Y", arial7)));
                    ptable.AddCell(pcell);
                    pcell = new PdfPCell(new Phrase(new Chunk("C * Y", arial7)));
                    ptable.AddCell(pcell);
                    for (int rows = 0; rows < this.dataX.Length; rows++)
                    {
                        pcell = new PdfPCell(new Phrase(new Chunk(this.dataX[rows].ToString(), arial7)));
                        ptable.AddCell(pcell);
                        pcell = new PdfPCell(new Phrase(new Chunk(this.dataY[rows].ToString(), arial7)));
                        ptable.AddCell(pcell);
                        pcell = new PdfPCell(new Phrase(new Chunk(this.suku[rows].ToString(), arial7)));
                        ptable.AddCell(pcell);
                    }
                }
                else
                {
                    document.Add(new Paragraph("ax = " + this.a[0] + "; bx = " + this.b[0] + "; orde-x = " + this.orde[0]));
                    document.Add(new Paragraph("ay = " + this.a[1] + "; by = " + this.b[1] + "; orde-y = " + this.orde[1]));
                    ptable = new PdfPTable(3);
                    iTextSharp.text.Font arial7 = FontFactory.GetFont("ARIAL", 7);
                    pcell = new PdfPCell(new Phrase(new Chunk("X", arial7)));
                    ptable.AddCell(pcell);
                    pcell = new PdfPCell(new Phrase(new Chunk("Y", arial7)));
                    ptable.AddCell(pcell);
                    pcell = new PdfPCell(new Phrase(new Chunk("integral arah Y", arial7)));
                    ptable.AddCell(pcell);
                    for (int rows = 0; rows < this.dataX.Length; rows++)
                    {
                        pcell = new PdfPCell(new Phrase(new Chunk(this.dataX[rows].ToString(), arial7)));
                        ptable.AddCell(pcell);
                        pcell = new PdfPCell(new Phrase(new Chunk(this.dataY[rows].ToString(), arial7)));
                        ptable.AddCell(pcell);
                        pcell = new PdfPCell(new Phrase(new Chunk(this.tempRes[rows].ToString(), arial7)));
                        ptable.AddCell(pcell);
                    }
                }
                document.Add(new Paragraph("\n"));
                document.Add(ptable);
                document.Add(new Paragraph("Hasil integral: " + this.result));

            }
            catch (DocumentException de)
            {

            }
            catch (IOException ioe)
            {

            }
            document.Close();
        }

    }
}
